package com.viking.car;

import java.io.*;
import java.util.Random;

public class MessageUtils {
    /**
     * 创建消息对象
     * @param content
     * @param commandId
     * @param sequenceId
     * @return
     * @throws java.io.UnsupportedEncodingException
     */
    public static Message generateMessage(String content,int commandId,int sequenceId,boolean response) throws UnsupportedEncodingException {
        int totalLength = Constants.HEADER_FOOTER_LENGTH;
        MessageBody body = new MessageBody(content,response);
        if (!response){
            int tokenLength = content.getBytes("UTF-8").length;
            totalLength += tokenLength;
        }else {
            totalLength += 4;//响应时是4个字节
            if (commandId == Constants.QUERYPOWER_RESP){
                totalLength += 2;//查询电量增加了两个字节
                body.setPower((short) new Random().nextInt(1000));
            }
        }
        MessageHeader header = new MessageHeader(totalLength,commandId,sequenceId);
        MessageFooter footer = new MessageFooter();
        Message message = new Message(header,body,footer);
        //System.out.println("生成消息:"+message);
        return message;
    }

    /**
     * 将消息转换为网络传输的字节数组
     * @param message
     * @return
     * @throws java.io.IOException
     */
    public static byte[] messageToBytes(Message message) throws IOException {
        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        DataOutputStream dos = new DataOutputStream(baos);
        //header
        dos.writeInt(message.getMessageHeader().getPackage_Header());
        dos.writeInt(message.getMessageHeader().getTotal_Length());
        dos.writeInt(message.getMessageHeader().getCommand_id());
        dos.writeInt(message.getMessageHeader().getSequence_id());
        dos.writeShort(message.getMessageHeader().getVersion());
        dos.writeInt(message.getMessageHeader().getReserved());
        //body
        if (!message.getMessageBody().isResponse()){
            dos.write(message.getMessageBody().getBody().getBytes("UTF-8"));
        }else {
            dos.writeInt(Integer.parseInt(message.getMessageBody().getBody()));
            Short power = message.getMessageBody().getPower();
            if (power != null){ //power不等于空，说明是查询电量时的响应消息
                dos.writeShort(power);
            }
        }
        //footer
        dos.writeShort(message.getMessageFooter().getCRC_CODE());
        dos.writeShort(message.getMessageFooter().getPackage_Footer());
        dos.flush();
        byte[] result = baos.toByteArray();
        //System.out.println("转换后"+bytesToMessage(result));
        return result;
    }

    /**
     * 将从网络读取到的字节数组转化为消息对象
     * @param bytes
     * @return
     */
    public static Message bytesToMessage(byte[] bytes,boolean response){
        //System.out.println("消息字节数组长度:"+bytes.length);
        ByteArrayInputStream bais = new ByteArrayInputStream(bytes);
        DataInputStream dis = new DataInputStream(bais);
        Message message = new Message();
        try {
            MessageHeader header = new MessageHeader();
            header.setPackage_Header(dis.readInt());
            header.setTotal_Length(dis.readInt());
            header.setCommand_id(dis.readInt());
            header.setSequence_id(dis.readInt());
            header.setVersion(dis.readShort());
            header.setReserved(dis.readInt());
            message.setMessageHeader(header);
            byte[] temp = new byte[bytes.length-Constants.HEADER_FOOTER_LENGTH];
            dis.read(temp);
            MessageBody body = null;
            if (!response){
                body = new MessageBody(new String(temp,"UTF-8"));
            } else if(header.getCommand_id() == Constants.QUERYPOWER_RESP){//查询电量返回值
                byte[] intByteArr = new byte[4];
                byte[] shortByteArr = new byte[2];
                System.arraycopy(temp,0,intByteArr,0,4);
                System.arraycopy(temp,4,shortByteArr,0,2);
                body = new MessageBody(String.valueOf(bytesToInt(intByteArr)),bytesToShort(shortByteArr));
            }else{
                body = new MessageBody(String.valueOf(bytesToInt(temp)));
            }
            message.setMessageBody(body);
            MessageFooter footer = new MessageFooter();
            footer.setCRC_CODE(dis.readShort());
            footer.setPackage_Footer(dis.readShort());
            message.setMessageFooter(footer);
            if (footer.getPackage_Footer() != Constants.PACKAGE_FOOTER){
                throw new IOException("Package_Footer值错误!");
            }
            return message;
        } catch (IOException e) {
            e.printStackTrace();
            return null;
        }
    }

    private static short bytesToShort(byte[] shortByteArr) {
        ByteArrayInputStream bais = new ByteArrayInputStream(shortByteArr);
        DataInputStream dis = new DataInputStream(bais);
        short result = 0;
        try {
            result = dis.readShort();
        } catch (IOException e) {
            e.printStackTrace();
        }
        //System.out.println("转换成int后："+result);
        return result;
    }

    /**
     * 将4字节数组转化为整型
     * @param bytes
     * @return
     */
    public static int bytesToInt(byte[] bytes){
        ByteArrayInputStream bais = new ByteArrayInputStream(bytes);
        DataInputStream dis = new DataInputStream(bais);
        int result = 0;
        try {
            result = dis.readInt();
        } catch (IOException e) {
            e.printStackTrace();
        }
        //System.out.println("转换成int后："+result);
        return result;
    }

    /**
     * 关闭流
     * @param closeable
     */
    public static void close(Closeable closeable){
        if (closeable != null){
            try {
                closeable.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

    /**
     * 读取网络传输过来的消息字节数组
     * @param ins
     * @return
     * @throws java.io.IOException
     */
    public static byte[] readMessageBytes(InputStream ins) throws IOException {
        PushbackInputStream pis = new PushbackInputStream(ins,8);
        byte[] temp1 = new byte[4];
        byte[] temp2 = new byte[4];
        pis.read(temp1,0,4);//读取前4个字节,Package_Header
        if (bytesToInt(temp1) != Constants.PACKAGE_HEADER){
            //throw new IOException("头信息PACKAGE_HEADER错误!");
            System.out.println("不是正确的消息，丢弃该数据");
            //下面为调试代码,查看到底是什么错误信息
            FileOutputStream fos = new FileOutputStream("d:\\b");
            pis.unread(temp1);
            byte[] b = new byte[1024];
            while (pis.read(b,0,b.length) != -1){
                fos.write(b);
            }
            fos.flush();
            fos.close();
            return null;
        }
        pis.read(temp2,0,4);//读取第二个4字节,得到消息的长度
        int length = bytesToInt(temp2);
        if (length < Constants.HEADER_FOOTER_LENGTH){
            throw new IOException("消息长度错误！小于头和尾的总长度!");
        }
        pis.unread(temp2);
        pis.unread(temp1);
        byte[] bytes = new byte[length];
        pis.read(bytes, 0, bytes.length);//读取整个消息
        //close(pis);//不能关掉啊，擦
        return bytes;
    }
}
